package org.happen.android.core.data.image;

import java.io.File;
import java.net.URL;
import java.util.List;

import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.graphics.Bitmap;
import android.util.Log;

public class ImageDbCacheManager
{
	private static final String TAG = "ImageDbCacheManager";
	private DBClient dbClient;
	private static ImageDbCacheManager instance = null;
	private Context mContext;
	private FilesUtils filesUtils;
	private int mode = 1;

	private int max_Count = 100;

	private long delay_Millisecond = 259200000L;

	private long max_Memory = 3145728L;
	public static final int MODE_LEAST_RECENTLY_USED = ImageCacheManager.MODE_LEAST_RECENTLY_USED;
	public static final int MODE_FIXED_TIMED_USED = ImageCacheManager.MODE_FIXED_TIMED_USED;
	public static final int MODE_FIXED_MEMORY_USED = ImageCacheManager.MODE_FIXED_MEMORY_USED;
	public static final int MODE_NO_CACHE_USED = ImageCacheManager.MODE_NO_CACHE_USED;

	private ImageDbCacheManager(Context context, int mode, String tag)
	{
		this.mode = mode;
		this.mContext = context;
		this.filesUtils = new FilesUtils(context);
		if (mode == MODE_LEAST_RECENTLY_USED)
			this.dbClient = new DBClient(this.mContext, "least_recently_used", tag);
		else if (mode == MODE_FIXED_TIMED_USED)
			this.dbClient = new DBClient(this.mContext, "fixed_timed_used", tag);
		else if (mode == MODE_FIXED_MEMORY_USED)
			this.dbClient = new DBClient(this.mContext, "fixed_memory_used", tag);
	}

	/**
	 * get ImageDbCacheManager create table name = mode + tag
	 * 
	 * @ReqParam context
	 * @ReqParam mode the mode is
	 * MODE_LEAST_RECENTLY_USED,MODE_FIXED_TIMED_USED,
	 * MODE_FIXED_MEMORY_USED,MODE_NO_CACHE_USED
	 * @ReqParam tag
	 * @return
	 */
	public static synchronized ImageDbCacheManager getImageCacheService(Context context, int mode, String tag)
	{
		if (instance == null)
		{
			instance = new ImageDbCacheManager(context, mode, tag);
		}
		return instance;
	}

	public DBClient getDbClient()
	{
		return dbClient;
	}

	/***
	 * use url to search in the database. If not exist in db, then download from
	 * network
	 * 
	 * @ReqParam url
	 * @return
	 */
	//	public CacheInfo downloadImage(URL url) {
	//		return downloadImage(url,null);
	//	}

	public CacheInfo downloadImage(URL url)
	{
		//		Date d1=new Date();
		//		Log.i(TAG,"d1 = " + d1.getTime());

		CacheInfo cacheInfo = null;

		switch (this.mode)
		{
			case MODE_LEAST_RECENTLY_USED:
				cacheInfo = new LRU(url).execute();
				break;
			case MODE_FIXED_TIMED_USED:
				cacheInfo = new FTU(url).execute();
				break;
			case MODE_FIXED_MEMORY_USED:
				cacheInfo = new FMU(url).execute();
				break;
			case MODE_NO_CACHE_USED:
				cacheInfo = this.filesUtils.downloadImage(url);

			default:
				break;
		}
		if (cacheInfo != null)
		{
			cacheInfo.getValue();
		}
		//		Date d2=new Date();
		//		Log.i(TAG,"d2 = " + d2.getTime());
		return cacheInfo;
	}

	/**
	 * use MODE_LEAST_RECENTLY_USED mode set the max number of cache data in
	 * database
	 * 
	 * @ReqParam max_num
	 */
	public void setMax_num(int max_num)
	{
		this.max_Count = max_num;
	}

	/**
	 * use MODE_FIXED_TIMED_USED mode. set the last create date of image
	 * download from nwtwork. If the create date of image is before the delay
	 * millisecond from now ,the cache delete.
	 * 
	 * @ReqParam delay_millisecond
	 */
	public void setDelay_millisecond(long delay_millisecond)
	{
		this.delay_Millisecond = delay_millisecond;
	}

	/**
	 * use MODE_FIXED_MEMORY_USED mode for memory set the max file size of the
	 * cache image. If the image size > max, then delete. Or if the total size
	 * of the cache image size > max, delete the max image
	 * 
	 * @ReqParam max_Memory
	 */
	public void setMax_Memory(long max_Memory)
	{
		this.max_Memory = max_Memory;
	}

	private class FMU implements IDownload
	{
		URL url = null;

		//		int flag = ImageCacheManager.FLAG_DOWNLOAD_METHOD_HTTP;

		FMU(URL url)
		{
			this.url = url;
		}

		public CacheInfo execute()
		{
			SQLiteDatabase db = ImageDbCacheManager.this.dbClient.getSQLiteDatabase();
			db.beginTransaction();
			CacheInfo cacheInfo = null;
			try
			{
				cacheInfo = ImageDbCacheManager.this.dbClient.select(this.url.toString(), db);
				List<CacheInfo> cacheInfos = ImageDbCacheManager.this.dbClient.selectAll(db);
				Bitmap bitmap = null;
				if (cacheInfo != null)
				{
					try
					{
						bitmap = ImageDbCacheManager.this.filesUtils.readImage(cacheInfo.getFileName());
					} catch (OutOfMemoryError err)
					{
						Log.e(TAG, "out of memory error", err);
					}
				}

				if (cacheInfo == null || bitmap == null)
				{
					cacheInfo = ImageDbCacheManager.this.filesUtils.downloadImage(this.url);
					if (cacheInfo == null)
					{
						return null;
					}
					if (cacheInfo.getFileSize() > ImageDbCacheManager.this.max_Memory)
					{
						Log.i(ImageDbCacheManager.this.mContext.getPackageName(), "the image resource" + cacheInfo.getUrl().toString() + " need more  storage than "
								+ ImageDbCacheManager.this.max_Memory + "B");
					} else
					{
						if ((cacheInfos != null) && (cacheInfos.size() > 0))
						{
							long sumSize = 0L;
							while (cacheInfos.size() > 0)
							{
								int i = 0;
								for (int size = cacheInfos.size(); i < size; ++i)
								{
									CacheInfo tempCache = (CacheInfo) cacheInfos.get(i);
									sumSize += tempCache.getFileSize();
								}
								if (sumSize + cacheInfo.getFileSize() <= ImageDbCacheManager.this.max_Memory)
								{
									break;
								}
								CacheInfo deleteCacheInfo = maxSize(cacheInfos);
								if (!ImageDbCacheManager.this.dbClient.delete(deleteCacheInfo.getUrl().toString(), db))
								{

									continue;
								}

								ImageDbCacheManager.this.filesUtils.deleteImage(deleteCacheInfo.getFileName());

								cacheInfos.remove(deleteCacheInfo);
							}

						}

						if (ImageDbCacheManager.this.dbClient.insert(cacheInfo, db))
							;
						//TODO
						//							ImageDbCacheManager.this.filesUtils.saveImage(
						//									cacheInfo.getValue(),
						//									cacheInfo.getFileName());
					}
				} else
				{

					if (bitmap != null)
						cacheInfo.setValue(bitmap);
				}
			} finally
			{
				db.setTransactionSuccessful();
				db.endTransaction();
			}
			return cacheInfo;
		}

		private CacheInfo maxSize(List<CacheInfo> cacheInfos)
		{
			long max = ((CacheInfo) cacheInfos.get(0)).getFileSize();
			CacheInfo deleteCache = (CacheInfo) cacheInfos.get(0);
			int i = 0;
			for (int size = cacheInfos.size(); i < size; ++i)
			{
				CacheInfo tempCache = (CacheInfo) cacheInfos.get(i);
				if (tempCache.getFileSize() > max)
				{
					deleteCache = tempCache;
				}
			}
			return deleteCache;
		}
	}

	private class FTU implements IDownload
	{
		URL url = null;

		//		int flag = ImageCacheManager.FLAG_DOWNLOAD_METHOD_HTTP;
		FTU(URL url)
		{
			this.url = url;
		}

		public CacheInfo execute()
		{
			CacheInfo cacheInfo = null;
			SQLiteDatabase db = ImageDbCacheManager.this.dbClient.getSQLiteDatabase();
			db.beginTransaction();
			try
			{
				cacheInfo = ImageDbCacheManager.this.dbClient.select(this.url.toString(), db);
				Bitmap bitmap = null;
				if (cacheInfo != null)
				{
					try
					{
						bitmap = ImageDbCacheManager.this.filesUtils.readImage(cacheInfo.getFileName());
					} catch (OutOfMemoryError err)
					{
						Log.e(TAG, "out of memory error", err);
					}
				}

				if (cacheInfo == null || bitmap == null)
				{
					cacheInfo = ImageDbCacheManager.this.filesUtils.downloadImage(this.url);
					if (cacheInfo == null)
						return null;
					if (ImageDbCacheManager.this.dbClient.insert(cacheInfo, db))
						;
					//TODO
					//						ImageDbCacheManager.this.filesUtils.saveImage(
					//								cacheInfo.getValue(), cacheInfo.getFileName());
				} else
				{
					ImageDbCacheManager.this.dbClient.update(System.currentTimeMillis(), this.url.toString(), db);

					cacheInfo.setValue(bitmap);
				}
				List<CacheInfo> cacheInfos = ImageDbCacheManager.this.dbClient.selectAll(db);
				if (cacheInfos != null)
				{
					int i = 0;
					for (int size = cacheInfos.size(); i < size; ++i)
					{
						CacheInfo tempCache = (CacheInfo) cacheInfos.get(i);

						if ((tempCache.getCreatAt() + ImageDbCacheManager.this.delay_Millisecond >= System.currentTimeMillis())
								|| (!ImageDbCacheManager.this.dbClient.delete(tempCache.getUrl().toString(), db)))
						{

							continue;

						}
						ImageDbCacheManager.this.filesUtils.deleteImage(tempCache.getFileName());
					}
				}

			} finally
			{
				db.setTransactionSuccessful();
				db.endTransaction();
			}
			return cacheInfo;
		}
	}

	private class LRU implements IDownload
	{
		URL url = null;

		//		int flag = ImageCacheManager.FLAG_DOWNLOAD_METHOD_HTTP;

		LRU(URL url)
		{
			this.url = url;
			//			flag = ImageCacheManager.FLAG_DOWNLOAD_METHOD_FTP;
		}

		public CacheInfo execute()
		{
			SQLiteDatabase db = ImageDbCacheManager.this.dbClient.getSQLiteDatabase();
			//			db.beginTransaction();
			CacheInfo cacheInfo = null;
			try
			{
				cacheInfo = ImageDbCacheManager.this.dbClient.select(this.url.toString(), db);
				//				List cacheInfos = ImageDbCacheManager.this.dbClient.selectAll(db);
				int countInDb = ImageDbCacheManager.this.dbClient.getCountInDb(db);
				Log.i(TAG, " &&&&&&   count = " + countInDb);

				//				Bitmap bitmap = null;
				//				if(cacheInfo != null){
				//					try{
				//						bitmap = ImageDbCacheManager.this.filesUtils
				//								.readImage(cacheInfo.getFileName());
				//					}catch(OutOfMemoryError err){
				//						Log.e(TAG,"out of memory error", err);
				//					}
				//				}

				boolean ifExist = false;
				if (cacheInfo != null)
				{
					//					cacheInfo.setValue(bitmap);
					String fileName = cacheInfo.getFileName();
					File file = mContext.getFileStreamPath(fileName);
					if (file.exists())
					{
						if (file.length() > 10)
						{
							ImageDbCacheManager.this.dbClient.update(cacheInfo.getUsetimes() + 1, this.url.toString(), db);
							ifExist = true;
						} else
						{
							file.delete();
						}
					}

					//					int i = 0;
					//					for (int size = cacheInfos.size(); i < size; ++i) {
					//						CacheInfo temp = (CacheInfo) cacheInfos.get(i);
					//						if (this.url.toString()
					//								.equals(temp.getUrl().toString())){
					//							ImageDbCacheManager.this.dbClient.update(temp
					//									.getUsetimes() + 1,
					//									this.url.toString(), db);
					//							break;
					//						}
					//							
					//						else
					//							ImageDbCacheManager.this.dbClient.update(temp
					//									.getUsetimes() + 1, temp.getUrl()
					//									.toString(), db);
					//					}
				}

				if (!ifExist)
				{ //不存在图片,则下载
					cacheInfo = ImageDbCacheManager.this.filesUtils.downloadImage(this.url);
					if (cacheInfo == null)
						return null;
					if (countInDb >= ImageDbCacheManager.this.max_Count)
					{ //大于最大值时，删除使用最少使用的项

						List<CacheInfo> deleteCaches = dbClient.selectMinUsetimesCacheList(db);
						//						usetimes = deletedCache.getUsetimes();
						int size = deleteCaches.size();

						if (size > 0)
						{
							int usetimes = deleteCaches.get(0).getUsetimes();
							boolean ifDeleted = ImageDbCacheManager.this.dbClient.deleteLFUList(usetimes, db);
							if (ifDeleted)
							{
								for (int i = 0; i < size; ++i)
								{
									CacheInfo deletedCache = deleteCaches.get(i);
									if (ImageDbCacheManager.this.dbClient.delete(deletedCache.getUrl().toString(), db))
									{
										ImageDbCacheManager.this.filesUtils.deleteImage(deletedCache.getFileName());
										//										if (ImageDbCacheManager.this.dbClient.insert(
										//												cacheInfo, db)) {
										//											ImageDbCacheManager.this.filesUtils.saveImage(
										//													cacheInfo.getValue(),
										//													cacheInfo.getFileName());
										//										}
									}
								}
							}
						}
					}
					//					else if () {
					//						ImageDbCacheManager.this.filesUtils.saveImage(
					//								cacheInfo.getValue(), cacheInfo.getFileName());
					//					}

					try
					{
						ImageDbCacheManager.this.dbClient.delete(cacheInfo.getUrl().toString(), db);
					} catch (Exception ex)
					{
						Log.i(TAG, "exception when delete file = " + cacheInfo.getUrl().toString(), ex);
					}

					ImageDbCacheManager.this.dbClient.insert(cacheInfo, db);
				}
			} finally
			{
				//				db.setTransactionSuccessful();
				//				db.endTransaction();
			}
			return cacheInfo;
		}
	}
}